home *** CD-ROM | disk | FTP | other *** search
- /* X M S L I B . c -- Extended memory (XMS 2.0+) support functions
- * ---------------------------------------------------------------
- *
- * $Revision: 1.0 $
- * $Date: 28 Feb 1992 8:54:56 $
- * $Log: F:/XMSLIB/VCS/XMSLIB.C_V $
- *
- * Rev 1.0 28 Feb 1992 8:54:56
- * Initial revision.
- *
- * ---------------------------------------------------------------
- */
-
- /* ------------------------ Pragmas -------------------------- */
-
- /* ---------------------- Include files ----------------------- */
- #include <stdlib.h>
- #include <string.h>
- #if defined ( _M_DEBUG )
- #include <ctype.h>
- #endif
- #include <dos.h>
-
- #include "xmslib.h"
-
- /* -------------------- Local definitions --------------------- */
- #define _CPYR_ " Copyright (C) 1992 M.G.A.Wilson"
-
- #if defined ( M_I86SM ) // Microsoft, small
- #define APICALL call far ptr [mpXMSAPI]
- #define EAPICALL call far ptr es:[mpXMSAPI]
- #elif (defined ( __SMALL__ ) || defined (__COMPACT__)) // Borland, small
- #define APICALL call dword ptr mpXMSAPI
- #define EAPICALL call dword ptr es:mpXMSAPI
- #elif (defined ( __LARGE__ ) || defined ( M_I86LM )) // Large
- #define APICALL call [mpXMSAPI]
- #define EAPICALL call es:[mpXMSAPI]
- #else
- #error Unsupported compiler or memory model.
- #endif
-
- #define H_640K 0 // XMS move handle for 640K conventional memory
-
- typedef struct tagXMSMOVE // Extended Memory Move Structure
- { // ------------------------------
- DWORD ulLength; // Number of bytes to transfer
- WORD uSrcHdl; // Handle to source block
- DWORD ulSrcOfs; // Offset into source block
- WORD uDestHdl; // Handle to destination block
- DWORD ulDestOfs; // Offset into destination block
- }
- XMSMOVE_T; // Handle(s) == H_640K for conventional memory
-
- typedef struct tagXMSCTRL // Extended Memory Control structure
- { // ---------------------------------
- WORD uHandle; // Handle to the actual XMS block
- WORD uHiWater; // `High water' mark: offset of 1st free byte
- WORD uNumK; // Number of Kbytes in the block (1..64)
- BOOLEAN fCompacted; // TRUE if the free blocks have been compacted
- }
- XMSCTRL_T;
-
- typedef struct tagXMSBLOCKHEADER // Extended Memory Allocation Block Header
- { // ---------------------------------------
- WORD uLength; // Number of data bytes in the block
- WORD uData; // Data, or number of free data bytes, if
- } // <uLength> is 0
- XMSBLOCKHEADER_T;
-
- /* ------------------- Function prototypes -------------------- */
-
- /* ------------------------- Globals -------------------------- */
- static const char mszIdent[] = { "@(#)XMSLIB v1.00" _CPYR_ };
-
- static DWORD mpXMSAPI; // XMS API entry point
- static WORD muXMSerrCode; // Error code returned by API call
-
- static WORD muCtrlBlks = 0, // Number of XMS control blocks
- muCurrCtrlBlk = 0; // Current XMS control block
- static XMSCTRL_T * mpXMCtrl = NULL; // Pointer to (array of) ctrl blocks
-
- /* ------------------------------------------------------------
-
- The control structure maintained in conventional RAM looks like this:
-
-
- ┌───────────────────┐
- Hi│ Control block N │ Each control block contains a handle to an
- ├───────────────────┤ XMS memory block (16-bit word) and the current
- . . . `high water' mark in the control block, that
- ├───────────────────┤ is, the offset of the first byte where
- │ Control block 1 │ allocated data can be placed.
- ├───────────────────┤
- Lo│ Control block 0 │ The number of blocks is fixed by XMSopen()
- └───────────────────┘
-
-
- The structure of a partially-used block in XMS memory looks like this:
-
- ┌─┬────┬─┬────────┬─┬──┬─┬───────┬─┬────────────┬─┬────────────────────┐
- │a│XXXX│b│XXXXXXXX│0│cX│d│XXXXXXX│e│XXXXXXXXXXXX│0│00000000000000000000│
- └─┴────┴─┴────────┴─┴──┴─┴───────┴─┴────────────┴─┴────────────────────┘
-
- Here, letters `a',`b' etc. represent the start of allocation units. Each
- contains a 16-bit word holding the LENGTH OF DATA FOLLOWING THE WORD. The
- total length of the unit is therefore (length)+2 bytes. If a length is
- marked as 0, then the block is free and can be (re)used for storage.
-
- If it has never been used, then the first word of the data will also be 0,
- and all space up to the end of the XMS block will thterefore be available.
-
- If the block has been previously used and then freed, the length of the
- (old) block will be stored in the first word of the data. A check for a
- fit of the newly-allocated block can then be made (which may generate a
- new, smaller freed block if the fit is not exact).
-
- ------------------------------------------------------------ */
-
- // X M S g e t A P I a d d r e s s
- // -------------------------------
- // Locates the call gate to the XMS application programming interface
- // and stores it in the global <mpXMSAPI>
- //
- static void _near XMSgetAPIaddress (void)
- {
- _asm {
- mov ax,4310h
- int 2Fh
- mov word ptr [mpXMSAPI],bx
- mov word ptr [mpXMSAPI + 2],es
- }
- }
-
- // X M S g e t F r e e M e m
- // -------------------------
- //
- static WORD _near XMSgetFreeMem (WORD * puLargestBlk)
- {
- WORD uTotal, uLargest;
-
- _asm {
- mov ah,8
- APICALL
- mov [muXMSerrCode],bx
- mov uLargest,ax
- mov uTotal,dx
- }
- *puLargestBlk = uLargest;
- return uTotal;
- }
-
- // X M S a l l o c B l o c k
- // -------------------------
- // Allocate a block of <uKbytes> K bytes from the XMS memory
- //
- // Returns:
- // Handle to the block, or 0 if none could be allocated
- //
- static WORD _near XMSallocBlock (WORD uKbytes)
- {
- WORD hXM = 0; // The handle
-
- _asm {
- mov ah,9
- mov dx,uKbytes
- APICALL
- mov [muXMSerrCode],bx
- or ax,ax
- jz AllocOver
- mov hXM,dx
- }
-
- AllocOver:
- return hXM;
- }
-
- // X M S f r e e B l o c k
- // -----------------------
- // Free a block of XMS memory accessed through handle <hXM>
- //
- // Returns:
- // 1 if successfully freed, 0 if not
- //
- static int _near XMSfreeBlock (WORD hXM)
- {
- int fSuccess;
-
- _asm {
- mov ah,0Ah
- mov dx,hXM
- APICALL
- mov [muXMSerrCode],bx
- mov fSuccess,ax
- }
-
- return fSuccess;
- }
-
- // X M S m o v e
- // -------------
- // Transfer data to or from XMS memory
- //
- // Argument:
- // <pXMSmv> Pointer to XMS move structure (see XMS spec)
- //
- // Returns:
- // 1 for success, 0 on error
- //
- static int _near XMSmove (XMSMOVE_T _far * pXMSmv)
- {
- int fSuccess;
- unsigned uSegment = FP_SEG(pXMSmv),
- uOffset = FP_OFF(pXMSmv);
- _asm {
- mov ax,ds
- mov es,ax
- push ds
- push si
- mov si,uOffset
- mov ax,uSegment
- mov ds,ax
- mov ah,0Bh
- EAPICALL
- mov es:[muXMSerrCode],bx
- pop si
- pop ds
- mov fSuccess,ax
- }
- return fSuccess;
- }
-
- // X M S a l l o c W r i t e
- // -------------------------
- // Write control information into XMS memory to mark an allocated block
- //
- // Arguments:
- // <hXM> Native (XMS-derived) handle to XMS memory block
- // <uOfs> Offset within the XMS block
- // <uBytes> Number of data bytes which the block will hold
- //
- // Returns:
- // Handle to memory, or XMSHNULL on error
- //
- static XMSHANDLE _near XMSallocWrite (WORD hXM, WORD uOfs, WORD uBytes)
- {
- XMSBLOCKHEADER_T XMShdr;
- XMSMOVE_T XMSmv;
- XMSHANDLE xhXM = XMSHNULL;
-
- XMShdr.uLength = uBytes;
- XMShdr.uData = 0;
-
- XMSmv.ulLength = sizeof(XMSBLOCKHEADER_T);
- XMSmv.uSrcHdl = H_640K;
- XMSmv.ulSrcOfs = (DWORD)((char _far *)&XMShdr);
- XMSmv.uDestHdl = hXM;
- XMSmv.ulDestOfs = (DWORD)uOfs;
-
- if (XMSmove(&XMSmv))
- {
- xhXM = ((DWORD)hXM << 16);
- xhXM += uOfs;
- }
- return xhXM;
- }
-
- // C o a l e s c e F r e e U n i t s
- // ---------------------------------
- // Join contiguous freed blocks in an allocation unit into a single free block
- //
- // Argument:
- // <pXMCtrl> Pointer to memory control block
- //
- static void _near _fastcall CoalesceFreeUnits (XMSCTRL_T * pXMCtrl)
- {
- if (!pXMCtrl->fCompacted)
- {
- XMSBLOCKHEADER_T XMShdrThis,
- XMShdrNext;
- XMSMOVE_T XMSmv;
- WORD uOfs = 0,
- uRefOfs;
-
- #if (defined ( _M_DEBUG ) && defined ( _M_VERBOSE ))
- printf("\n--> COALESCING BLOCK WITH HANDLE %04x\n", pXMCtrl->uHandle);
- #endif
-
- XMSmv.ulLength = sizeof(XMSBLOCKHEADER_T);
-
- while (uOfs < pXMCtrl->uHiWater)
- {
- WORD uFreeLen = 0;
- BOOLEAN fBlockEnd = FALSE;
-
- XMSmv.uSrcHdl = pXMCtrl->uHandle;
- XMSmv.uDestHdl = H_640K;
- XMSmv.ulSrcOfs = uRefOfs = uOfs;
- XMSmv.ulDestOfs = (DWORD)((char _far *)&XMShdrThis);
-
- if (!XMSmove(&XMSmv))
- return;
-
- XMSmv.ulDestOfs = (DWORD)((char _far *)&XMShdrNext);
-
- if (XMShdrThis.uLength == 0)
- {
- WORD uExtraLen = 0;
-
- // This block is free: iterate through the following blocks,
- // accumulating the total free length...
- do
- {
- if (XMShdrThis.uData == 0) // Hit end of chain
- {
- uFreeLen = 0; // Original now marks end of chain
- fBlockEnd = TRUE;
- break;
- }
-
- uFreeLen += (XMShdrThis.uData + uExtraLen);
- uOfs += (XMShdrThis.uData + sizeof(WORD));
-
- if (uOfs >= pXMCtrl->uHiWater)
- {
- fBlockEnd = TRUE;
- break;
- }
-
- XMSmv.ulSrcOfs = uOfs;
-
- if (!XMSmove(&XMSmv)) // Read next header
- return;
-
- XMShdrThis = XMShdrNext;
-
- uExtraLen = sizeof(WORD); // Count 2 byte length on all but 1st block
- }
- while (XMShdrThis.uLength == 0);
-
- // Now update the *original* free block with the coalesced length
- XMShdrNext.uLength = 0;
- if (fBlockEnd == TRUE && uRefOfs == 0)
- // Special case -- all blocks empty
- XMShdrNext.uData = 0;
- else
- XMShdrNext.uData = uFreeLen;
- XMSmv.uSrcHdl = H_640K;
- XMSmv.ulSrcOfs = (DWORD)((char _far *)&XMShdrNext);
- XMSmv.uDestHdl = pXMCtrl->uHandle;
- XMSmv.ulDestOfs = uRefOfs;
-
- XMSmove(&XMSmv);
-
- if (fBlockEnd == TRUE)
- {
- // Update high water mark to new end of block
- pXMCtrl->uHiWater = uRefOfs;
- break;
- }
- }
- else
- uOfs += (XMShdrThis.uLength + sizeof(WORD));
- }
- pXMCtrl->fCompacted = TRUE;
- }
- }
-
- // X M S a l l o c P l a n B
- // -------------------------
- // Allocator called when we've hit the high water mark in the last XMS block
- //
- // Argument:
- // <uBytes> Number of data bytes for which storage is required
- //
- // Returns:
- // Handle to memory, or XMSHNULL on error
- //
- static XMSHANDLE _near XMSallocPlanB (WORD uBytes)
- {
- XMSCTRL_T * pXMCtrl = mpXMCtrl;
-
- for (muCurrCtrlBlk = 0;
- muCurrCtrlBlk < muCtrlBlks; // For each XMS block...
- muCurrCtrlBlk++, pXMCtrl++)
- {
- WORD uOfs = 0; // Start at the bottom...
- XMSBLOCKHEADER_T XMShdr;
- XMSMOVE_T XMSmv;
-
- CoalesceFreeUnits(pXMCtrl);
-
- XMSmv.ulLength = sizeof(XMSBLOCKHEADER_T);
- XMSmv.uSrcHdl = pXMCtrl->uHandle;
- XMSmv.uDestHdl = H_640K;
- XMSmv.ulDestOfs = (DWORD)((char _far *)&XMShdr);
-
- do
- {
- XMSmv.ulSrcOfs = uOfs;
- XMSmove(&XMSmv);
-
- if (XMShdr.uLength == 0)
- {
- // This block is reusable
- if (XMShdr.uData >= uBytes + sizeof(WORD) + sizeof(WORD))
- {
- #if (defined ( _M_DEBUG ) && defined ( _M_VERBOSE ))
- printf("Reusing block of %04x bytes at %04x : New blocks %04x and %04x\n",
- XMShdr.uData, uOfs, uBytes, XMShdr.uData - uBytes - sizeof(WORD));
- #endif
- // Got space in middle of block -- write a new free block beyond it
- XMShdr.uData -= (uBytes + sizeof(WORD));
- XMSmv.uDestHdl = XMSmv.uSrcHdl;
- XMSmv.uSrcHdl = H_640K;
- XMSmv.ulSrcOfs = XMSmv.ulDestOfs;
- XMSmv.ulDestOfs = uOfs + uBytes + sizeof(WORD);
- XMSmove(&XMSmv);
-
- return XMSallocWrite(pXMCtrl->uHandle, uOfs, uBytes);
- }
- else
- {
- // Not big enough for allocation
- if (XMShdr.uData == 0)
- {
- // Block has never been used; work out length
- WORD uLen = 0xFFFF - uOfs;
-
- if (uLen < uBytes + sizeof(WORD) - 1)
- // No space in this block; try next
- break;
-
- // Got space at end of block
- pXMCtrl->uHiWater = uOfs + uBytes + sizeof(WORD);
- return XMSallocWrite(XMSmv.uSrcHdl, uOfs, uBytes);
- }
-
- // Skip to next
- uOfs += XMShdr.uData;
- }
- }
- else
- // This block ain't reusable: skip to next
- uOfs += XMShdr.uLength;
-
- uOfs += sizeof(WORD);
- }
- while (uOfs < pXMCtrl->uHiWater);
- }
- muCurrCtrlBlk = 0;
- return XMSHNULL;
- }
-
- // -----------------------------------------------------------------------
- // ----- E x t e r n a l l y - v i s i b l e f u n c t i o n s -----
- // -----------------------------------------------------------------------
-
- // X M S i n s t a l l e d
- // -----------------------
- // Returns:
- // 1 if XMS memory is installed, else 0
- //
- int XMSinstalled (void)
- {
- int fInstalled;
-
- _asm {
- mov ax,4300h
- int 2Fh
- and ax,0080h
- mov cl,7
- shr al,cl
- mov fInstalled,ax
- }
-
- return fInstalled;
- }
-
- // X M S g e t V e r s i o n
- // -------------------------
- // Gets the version of XMS memory driver (e.g. HIMEM.SYS) in use
- //
- // Returns:
- // BCD coded number (e.g. v3.21 -> 0x0321), or 0 if not installed or
- // the XMS library's XMSopen() function has not been called.
- //
- WORD XMSgetVersion (void)
- {
- WORD uVersion = 0;
-
- if (XMSinstalled() && mpXMSAPI != 0L)
- {
- _asm {
- mov ah,0
- APICALL
- mov uVersion,bx
- }
- }
- return uVersion;
- }
-
- // X M S o p e n
- // -------------
- // `Open communications' with extended memory
- //
- // Argument:
- // <uKbytes> Number of Kbytes of extended memory to use.
- //
- // Returns:
- // 1 for success
- // 0 for failure
- //
- // Notes:
- // A value of 0 for <uKbytes> will attempt to use *all* available XMS memory.
- // The call will fail if the entire amount requested can not be obtained.
- // At least 64K extended memory must be available as a contiguous block.
- //
- int XMSopen (WORD uKbytes)
- {
- if (muCtrlBlks == 0)
- {
- WORD uKlargestAvail,
- uLastK;
-
- XMSgetAPIaddress();
- XMSgetFreeMem(&uKlargestAvail);
-
- if (uKbytes == 0)
- {
- if (uKlargestAvail >= 64)
- muCtrlBlks = (uKlargestAvail / 64);
- }
- else if (uKlargestAvail >= uKbytes)
- muCtrlBlks = (uKbytes / 64) + 1;
-
- if ((uLastK = (uKbytes % 64)) == 0)
- uLastK = 64;
-
- if (muCtrlBlks > 0)
- {
- muCurrCtrlBlk = 0;
-
- if ((mpXMCtrl = (XMSCTRL_T *)calloc(muCtrlBlks, sizeof(XMSCTRL_T)))
- != NULL)
- {
- // XMS control blocks are pre-filled with zeroes. Now do the
- // actual carving up of the extended memory...
-
- XMSCTRL_T * pXMCtrl = mpXMCtrl;
- WORD uCount;
-
- for (uCount = 0; uCount < muCtrlBlks; uCount++)
- {
- WORD uNumK = (uCount == muCtrlBlks - 1 ? uLastK : 64);
- WORD uHandle = XMSallocBlock(uNumK);
-
- if (uHandle > 0)
- {
- pXMCtrl->uHandle = uHandle;
- pXMCtrl->uNumK = uNumK;
- pXMCtrl->fCompacted = TRUE;
- pXMCtrl++;
- }
- else
- {
- muCtrlBlks = uCount;
- break;
- }
- }
- }
- else
- muCtrlBlks = 0;
- }
-
- return(muCtrlBlks > 0);
- }
-
- // XMSopen() already called with no intervening XMSclose()
- return 0;
- }
-
- // X M S c l o s e
- // ---------------
- // `Close communications' with XMS memory
- //
- // Returns:
- // 1 for success
- // 0 for failure
- //
- // Notes:
- // De-allocates *all* memory associated with XMSalloc()ed data
- //
- int XMSclose (void)
- {
- if (muCtrlBlks > 0)
- {
- WORD uCount = muCtrlBlks,
- uFreed = 0;
- XMSCTRL_T * pXMCtrl = mpXMCtrl + uCount;
-
- do
- {
- if (XMSfreeBlock(pXMCtrl->uHandle))
- uFreed++;
- pXMCtrl--;
- }
- while (uCount-- > 0);
-
- if (uFreed == muCtrlBlks)
- {
- free(mpXMCtrl);
- muCtrlBlks = 0;
- muCurrCtrlBlk = 0;
- mpXMCtrl = NULL;
- return 1;
- }
- }
- return 0;
- }
-
- // X M S a l l o c
- // ---------------
- // Allocate space for data in extended memory
- //
- // Argument:
- // <uBytes> Number of data bytes for which storage is required
- //
- // Returns:
- // Handle to memory, or XMSHNULL on error
- //
- // Notes:
- // Overhead is one (WORD) in XMS memory per entry
- //
- XMSHANDLE XMSalloc (WORD uBytes)
- {
- XMSCTRL_T * pXMCtrl = mpXMCtrl + muCurrCtrlBlk;
- XMSHANDLE xhXM = XMSHNULL;
- unsigned uHiWater = pXMCtrl->uHiWater,
- uNumK = pXMCtrl->uNumK;
-
- // Word-align
-
- if (uBytes % 2)
- uBytes++;
-
- // Check for wrap at 64K boundary
-
- while ((uBytes + uHiWater + sizeof(WORD) < uBytes) ||
- ((uNumK < 64) &&
- (uBytes + uHiWater + sizeof(WORD) > uNumK * 1024)))
- {
- if (++muCurrCtrlBlk == muCtrlBlks)
- return XMSallocPlanB(uBytes);
-
- pXMCtrl++;
- uHiWater = pXMCtrl->uHiWater;
- uNumK = pXMCtrl->uNumK;
- }
-
- xhXM = XMSallocWrite(pXMCtrl->uHandle, uHiWater, uBytes);
-
- if (xhXM != XMSHNULL)
- pXMCtrl->uHiWater = uHiWater + uBytes + sizeof(WORD);
- else
- muCurrCtrlBlk = 0;
-
- return xhXM;
- }
-
- // X M S f r e e
- // -------------
- // Free an allocation unit obtained with XMSalloc()
- //
- // Arguments:
- // <xhXM> Handle to XMS memory
- //
- // Returns:
- // 1 on success, 0 on failure
- //
- int XMSfree (XMSHANDLE xhXM)
- {
- XMSBLOCKHEADER_T XMShdr;
- XMSMOVE_T XMSmv;
-
- XMSmv.ulLength = sizeof(XMSBLOCKHEADER_T);
- XMSmv.uSrcHdl = (WORD)(xhXM >> 16);
- XMSmv.ulSrcOfs = (WORD)xhXM; // Get the length, too
- XMSmv.uDestHdl = H_640K;
- XMSmv.ulDestOfs = (DWORD)((char _far *)&XMShdr);
-
- if (XMSmove(&XMSmv))
- {
- XMShdr.uData = XMShdr.uLength; // Old len stored in 1st two data bytes
- XMShdr.uLength = 0; // Length now marked as zero = reusable
-
- XMSmv.uDestHdl = XMSmv.uSrcHdl;
- XMSmv.ulDestOfs = XMSmv.ulSrcOfs; // Write over length bytes
- XMSmv.uSrcHdl = H_640K;
- XMSmv.ulSrcOfs = (DWORD)((char _far *)&XMShdr);
-
- if (XMSmove(&XMSmv))
- {
- WORD uBlock;
- XMSCTRL_T * pXMCtrl = mpXMCtrl;
-
- for (uBlock = 0; uBlock < muCtrlBlks; uBlock++)
- {
- if (pXMCtrl->uHandle == XMSmv.uDestHdl)
- {
- pXMCtrl->fCompacted = FALSE;
- break;
- }
- pXMCtrl++;
- }
- return 1;
- }
- }
- return 0;
- }
-
- // X M S e r r o r C o d e
- // -----------------------
- // Get the error code associated with the most recent XMS API call
- //
- WORD XMSerrorCode (void)
- {
- return muXMSerrCode;
- }
-
- // X M S g e t L e n
- // -----------------
- // Get the length of the space associated with an XMS handle
- //
- // Arguments:
- // <xhXM> Handle to XMS memory
- //
- // Returns:
- // Length of data, or 0 on error
- //
- WORD XMSgetLen (XMSHANDLE xhXM)
- {
- WORD hXM = (WORD)(xhXM >> 16),
- uOfs = (WORD)xhXM,
- uBlock = 0,
- uLen = 0;
- XMSCTRL_T * pXMCtrl = mpXMCtrl;
-
- while (uBlock < muCtrlBlks && pXMCtrl->uHandle != hXM)
- {
- uBlock++;
- pXMCtrl++;
- }
-
- if (uBlock < muCtrlBlks)
- {
- XMSMOVE_T XMSmv;
-
- XMSmv.ulLength = sizeof(WORD);
- XMSmv.uSrcHdl = hXM;
- XMSmv.ulSrcOfs = uOfs;
- XMSmv.uDestHdl = H_640K;
- XMSmv.ulDestOfs = (DWORD)((char _far *)&uLen);
-
- XMSmove(&XMSmv);
- }
- return uLen;
- }
-
- // X M S g e t E x t
- // -----------------
- // Get data from XMS memory to conventional memory; extended version
- //
- // Arguments:
- // <pDest> Pointer to source buffer
- // <xhXM> Handle to XMS memory
- // <uSrcOfs> Offset of data in the stored block (0 = start)
- // <uBytes> Number of bytes to copy
- //
- // Returns:
- // 1 on success, 0 on failure
- //
- int XMSgetExt (void * pDest, XMSHANDLE xhXM, WORD uSrcOfs, WORD uBytes)
- {
- XMSMOVE_T XMSmv;
-
- XMSmv.ulLength = uBytes;
- XMSmv.uSrcHdl = (WORD)(xhXM >> 16);
- XMSmv.ulSrcOfs = (WORD)xhXM + sizeof(WORD) + uSrcOfs;
- XMSmv.uDestHdl = H_640K;
- XMSmv.ulDestOfs = (DWORD)((char _far *)pDest);
-
- return XMSmove(&XMSmv);
- }
-
- // X M S g e t
- // -----------
- // Get data from XMS memory to conventional memory
- //
- // Arguments:
- // <pDest> Pointer to source buffer
- // <xhXM> Handle to XMS memory
- //
- // Returns:
- // 1 on success, 0 on failure
- //
- // Notes:
- // Automatically sets number of bytes copied out to the number copied in.
- // Caller *must* ensure that buffer at <pDest> is big enough.
- //
- int XMSget (void * pDest, XMSHANDLE xhXM)
- {
- XMSMOVE_T XMSmv;
-
- XMSmv.ulLength = XMSgetLen(xhXM);
- XMSmv.uSrcHdl = (WORD)(xhXM >> 16);
- XMSmv.ulSrcOfs = (WORD)xhXM + sizeof(WORD);
- XMSmv.uDestHdl = H_640K;
- XMSmv.ulDestOfs = (DWORD)((char _far *)pDest);
-
- return XMSmove(&XMSmv);
- }
-
- // X M S p u t
- // -----------
- // Put data in XMS memory from conventional memory
- //
- // Arguments:
- // <xhXM> Handle to XMS memory
- // <pSrc> Pointer to source buffer
- // <uBytes> Bytes to copy
- //
- // Returns:
- // 1 on success, 0 on failure
- //
- int XMSput (XMSHANDLE xhXM, const void * pSrc, WORD uBytes)
- {
- XMSMOVE_T XMSmv;
-
- if (uBytes == 0)
- uBytes = XMSgetLen(xhXM);
- else if (uBytes % 2)
- uBytes++;
-
- XMSmv.ulLength = uBytes;
- XMSmv.uSrcHdl = H_640K;
- XMSmv.ulSrcOfs = (DWORD)((char _far *)pSrc);
- XMSmv.uDestHdl = (WORD)(xhXM >> 16);
- XMSmv.ulDestOfs = (WORD)xhXM + sizeof(WORD);
-
- return XMSmove(&XMSmv);
- }
-
- #if defined ( _M_DEBUG)
-
- // -----------------------------------------------------------------------
- // ------------- D e b u g g i n g f u n c t i o n s ---------------
- // -----------------------------------------------------------------------
-
- // X M S d u m p C o n t r o l B l o c k
- // -------------------------------------
- static void _near XMSdumpControlBlock (const XMSCTRL_T * pXMCtrl)
- {
- printf("%04x %04x (%5u) %04x (%5u)\n", pXMCtrl->uHandle, pXMCtrl->uHiWater,
- pXMCtrl->uHiWater, pXMCtrl->uNumK, pXMCtrl->uNumK);
- }
-
- // X M S d u m p E x t e n d e d M e m o r y B l o c k
- // ---------------------------------------------------
- static void _near XMSdumpExtendedMemoryBlock (const XMSCTRL_T * pXMCtrl)
- {
- XMSMOVE_T XMSmv;
- WORD uOfs = 0;
- union
- {
- XMSBLOCKHEADER_T XMShdr;
- unsigned char bBuffer[sizeof(WORD) + 16];
- }
- Data;
-
- if (pXMCtrl->uHiWater == 0) // Has never been used
- return;
-
- XMSmv.ulLength = sizeof(Data);
- XMSmv.uSrcHdl = pXMCtrl->uHandle;
- XMSmv.uDestHdl = H_640K;
- XMSmv.ulDestOfs = (DWORD)((char _far *)&Data);
-
- do
- {
- WORD uRemaining = pXMCtrl->uHiWater - uOfs;
-
- if (uRemaining < sizeof(Data))
- XMSmv.ulLength = uRemaining;
-
- XMSmv.ulSrcOfs = uOfs;
-
- if (XMSmove(&XMSmv))
- {
- WORD i,
- iMax = Data.XMShdr.uLength;
-
- if (iMax == 0)
- iMax = Data.XMShdr.uData;
-
- if (iMax > 16)
- iMax = 16;
-
- printf("%04x: %04x ", uOfs, Data.XMShdr.uLength);
- for (i = 0; i < 16; i++)
- if (i < iMax)
- printf("%02x ", Data.bBuffer[i + sizeof(WORD)]);
- else
- printf(" ");
- printf(" ");
- for (i = 0; i < iMax; i++)
- {
- unsigned char c = Data.bBuffer[i + sizeof(WORD)];
- printf("%c", iscntrl(c) ? '.' : c);
- }
- printf("\n");
- }
- else
- {
- printf("ERROR %04x\n", XMSerrorCode());
- break;
- }
-
- if (Data.XMShdr.uLength == 0)
- uOfs += Data.XMShdr.uData;
- else
- uOfs += Data.XMShdr.uLength;
-
- uOfs += sizeof(WORD);
- }
- while (uOfs < pXMCtrl->uHiWater &&
- (Data.XMShdr.uLength > 0 || Data.XMShdr.uData > 0));
- }
-
- // X M S d u m p
- // -------------
- void XMSdump (WORD uDumpFlags)
- {
- XMSCTRL_T * pXMCtrl;
- WORD uCtrlBlk;
-
- printf("\n*** XMS Dump ***\n\n");
-
- if (uDumpFlags & XMSDUMP_CTRL)
- {
- printf("Control blocks:\n\n");
- printf(" Num: Hdl MaxH (MaxD) NoKH (NoKD)\n");
-
- for (uCtrlBlk = 0, pXMCtrl = mpXMCtrl;
- uCtrlBlk < muCtrlBlks;
- uCtrlBlk++)
- {
- printf("%5u: ", uCtrlBlk);
- XMSdumpControlBlock(pXMCtrl++);
- }
- }
-
- if (uDumpFlags & XMSDUMP_DATA)
- {
- printf("\nExtended memory:");
-
- for (uCtrlBlk = 0, pXMCtrl = mpXMCtrl;
- uCtrlBlk < muCtrlBlks;
- uCtrlBlk++)
- {
- printf("\n\nBlock %5u:\n\n", uCtrlBlk);
- XMSdumpExtendedMemoryBlock(pXMCtrl++);
- }
- }
- printf("\n****************\n\n");
- }
-
- #endif // _M_DEBUG